home *** CD-ROM | disk | FTP | other *** search
/ World of Education / World of Education.iso / world_p / pcshx10b.zip / PCSHX10B.EXE / UTILS.EXE / UTILDOCS.EXE / SEDEXEC.C < prev   
C/C++ Source or Header  |  1987-12-25  |  34KB  |  883 lines

  1. /* sedexec.c -- execute compiled form of stream editor commands
  2.  
  3.    The single entry point of this module is the function execute(). It
  4. may take a string argument (the name of a file to be used as text)  or
  5. the argument NULL which tells it to filter standard input. It executes
  6. the compiled commands in cmds[] on each line in turn.
  7.    The function command() does most of the work. Match() and advance()
  8. are used for matching text against precompiled regular expressions and
  9. dosub() does right-hand-side substitution.  Getline() does text input;
  10. readout() and memcmp() are output and string-comparison utilities.  
  11.  
  12. ==== Written for the GNU operating system by Eric S. Raymond ==== */
  13.  
  14. #include <stdlib.h>
  15. #include <stdio.h>      /* {f}puts, {f}printf, getc/putc, f{re}open, fclose */
  16. #include <ctype.h>      /* for isprint(), isdigit(), toascii() macros */
  17. #include <string.h>
  18. #include "sed.h"        /* command type structures & miscellaneous constants */
  19.  
  20. /***** shared variables imported from the main ******/
  21.  
  22. /* main data areas */
  23. extern char     linebuf[];      /* current-line buffer */
  24. extern sedcmd   cmds[];         /* hold compiled commands */
  25. extern long     linenum[];      /* numeric-addresses table */
  26.  
  27. /* miscellaneous shared variables */
  28. extern int      nflag;          /* -n option flag */
  29. extern int      eargc;          /* scratch copy of argument count */
  30. extern sedcmd   *pending;       /* ptr to command waiting to be executed */
  31. extern char     bits[];         /* the bits table */
  32.  
  33. /***** end of imported stuff *****/
  34.  
  35. #define SetIgflag(c)    igflag = c
  36. #define RiteCase(c)     (igflag? tolower(c): c)
  37. #define ToLower(c)      (c | 0x20)   /* quick and dirty tolower */
  38.  
  39. #define TRUE            1
  40. #define FALSE           0
  41.  
  42. static char LTLMSG[]    = "sed: line too long\n";
  43.  
  44. static char     *spend;         /* current end-of-line-buffer pointer */
  45. static long     lnum = 0L;      /* current source line number */
  46.  
  47. /* append buffer maintenance */
  48. static sedcmd   *appends[MAXAPPENDS];   /* array of ptrs to a,i,c commands */
  49. static sedcmd   **aptr = appends;       /* ptr to current append */
  50.  
  51. /* genbuf and its pointers */
  52. static char     genbuf[GENSIZ];
  53. static char     *lcomend = genbuf + GENSIZ;
  54. static char     *loc1;
  55. static char     *loc2;
  56. static char     *locs;
  57.  
  58. /* input file buffering */
  59. static char     inbuffer[MAXIOBUF];
  60.  
  61. /* command-logic flags */
  62. static int      jump;                   /* jump to cmd's link address if set */
  63. static int      delete;                 /* delete command flag */
  64. static int      igflag;                 /* ignore case in matches */
  65. static int      cvcase;                 /* - = tolower, + = toupper */
  66.  
  67. /* tagged-pattern tracking */
  68. static char     *bracend[MAXTAGS];      /* tagged pattern start pointers */
  69. static char     *brastart[MAXTAGS];     /* tagged pattern end pointers */
  70. static char     *wordbeg[10];           /* $0 and $1 to $9             */
  71. static char     *wordend[10];
  72. static char     wordbuf[MAXWBUF];
  73. static char     *wordbufend = wordbuf + MAXWBUF;
  74. static int      wordcount;
  75.  
  76. void execute(file)
  77. /* execute the compiled commands in cmds[] on a file */
  78. char *file;             /* name of text source file to be filtered */
  79. {
  80.         register char           *p1, *p2;       /* dummy copy ptrs */
  81.         register sedcmd         *ipc;           /* ptr to current command */
  82.         char                    *execp;         /* ptr to source */
  83.         char                    *getline();     /* input-getting functions */
  84.         void                    command(), readout();
  85.  
  86.  
  87.         if (file != NULL)       /* filter text from a named file */ 
  88.                 if (freopen(file, "r", stdin) == NULL)
  89.                         fprintf(stderr, "sed: can't open %s\n", file);
  90.         setvbuf(stdin, inbuffer, _IOFBF, sizeof(inbuffer));
  91.  
  92.         if (pending)            /* there's a command waiting */
  93.         {
  94.                 ipc = pending;          /* it will be first executed */
  95.                 pending = FALSE;        /*   turn off the waiting flag */
  96.                 goto doit;              /*   go to execute it immediately */
  97.         }
  98.  
  99.         /* here's the main command-execution loop */
  100.         for(;;)
  101.         {
  102.  
  103.                 /* get next line to filter */
  104.                 if ((execp = getline(linebuf)) == BAD)
  105.                         return;
  106.                 spend = execp;
  107.  
  108.                 /* loop through compiled commands, executing them */
  109.                 for(ipc = cmds; ipc->command; )
  110.                 {
  111.                         SetIgflag(ipc->flags.igcase);
  112.                         cvcase = 0;
  113.                         /* all no-address commands are selected */
  114.                         if (ipc->addr1 && !selected(ipc))
  115.                         {
  116.                                 ipc++;
  117.                                 continue;
  118.                         }
  119.         doit:
  120.                         command(ipc);   /* execute the command pointed at */
  121.  
  122.                         if (delete)     /* if delete flag is set */
  123.                                 break;  /* don't exec rest of compiled cmds */
  124.  
  125.                         if (jump)       /* if jump set, follow cmd's link */
  126.                         {
  127.                                 jump = FALSE;
  128.                                 if ((ipc = ipc->u.link) == 0)
  129.                                 {
  130.                                         ipc = cmds;
  131.                                         break;
  132.                                 }
  133.                         }
  134.                         else            /* normal goto next command */
  135.                                 ipc++;
  136.                 }
  137.                 /* we've now done all modification commands on the line */
  138.  
  139.                 /* here's where the transformed line is output */
  140.                 if (!nflag && !delete)
  141.                 {
  142.                         for(p1 = linebuf; p1 < spend; p1++)
  143.                                 putc(*p1, stdout);
  144.                         putc('\n', stdout);
  145.                 }
  146.  
  147.                 /* if we've been set up for append, emit the text from it */
  148.                 if (aptr > appends)
  149.                         readout();
  150.  
  151.                 delete = FALSE; /* clear delete flag; about to get next cmd */
  152.         }
  153. }
  154.  
  155. int selected(ipc)
  156. /* is current command selected */
  157. sedcmd  *ipc;
  158. {
  159.         register char   *p1 = ipc->addr1;       /* point p1 at first address */
  160.         register char   *p2 = ipc->addr2;       /*   and p2 at second */
  161.         int             c;
  162.  
  163.         if (ipc->flags.inrange)
  164.         {
  165.                 if (*p2 == CLNUM)
  166.                 {
  167.                         c = p2[1];
  168.                         if ((c = lnum - linenum[c]) >= 0)
  169.                         {
  170.                                 ipc->flags.inrange = FALSE;
  171.                                 if (c>0)
  172.                                    return(ipc->flags.allbut);
  173.                         }
  174.                 }
  175.                 else if (*p2 != CEND && match(p2, 0))
  176.                         ipc->flags.inrange = FALSE;
  177.         }
  178.         else
  179.         {
  180.            if (*p1 == CEND)
  181.            {
  182.                 if (!lastline())
  183.                         return(ipc->flags.allbut);
  184.            }
  185.            else if (*p1 == CLNUM)
  186.            {
  187.                 c = p1[1];
  188.                 if (lnum != linenum[c])
  189.                 {
  190.                         return(ipc->flags.allbut);
  191.                 }
  192.            }
  193.            else if (!match(p1, 0))
  194.                         return(ipc->flags.allbut);
  195.            if (p2)
  196.            {
  197.                 if (*p2 == CEND)
  198.                         ipc->flags.inrange = TRUE;
  199.                 else if (*p2 == CLNUM)
  200.                 {
  201.                         c = p2[1];
  202.                         ipc->flags.inrange = (lnum < linenum[c]);
  203.                 }
  204.                 else
  205.                         ipc->flags.inrange = !match(p2,0);
  206.  
  207.            }
  208.         }
  209.  
  210.         return(!ipc->flags.allbut);
  211. }
  212.  
  213. int match(expbuf, gf)    /* uses genbuf */
  214. /* match RE at expbuf against linebuf; if gf set, copy linebuf from genbuf */
  215. char    *expbuf;
  216. {
  217.         register int    c;
  218.         register char   *p1, *p2;
  219.  
  220.         if (gf)
  221.         {
  222.                 if (*expbuf) return(FALSE);
  223.                 p1 = linebuf; p2 = genbuf;
  224.                 while (*p1++ = *p2++);
  225.                 locs = p1 = loc2;
  226.         }
  227.         else
  228.         {
  229.                 p1 = linebuf;
  230.                 locs = FALSE;
  231.         }
  232.  
  233.         p2 = expbuf;
  234.         if (*p2++)
  235.         {
  236.                 loc1 = p1;
  237.                 if(*p2 == CCHR && p2[1] != RiteCase(*p1))
  238.                         return(FALSE);          /* fail - 1st char is wrong */
  239.                 return(advance(p1, p2));        /* else try to match rest */
  240.         }
  241.  
  242.         /* quick check for 1st character if it's literal */
  243.         if (*p2 == CCHR)
  244.         {
  245.                 c = p2[1];              /* pull out character to search for */
  246.                 
  247.                 p1--;
  248.                 do {
  249.                         if (igflag)
  250.                            while (*++p1 && ToLower(*p1)!=c);
  251.                         else
  252.                            while (*++p1 && *p1!=c);
  253.                            
  254.                         if (*p1 && advance(p1, p2))    /* found it, match the rest */
  255.                                 return(loc1 = p1, 1);
  256.                 } while (*p1);
  257.                 
  258.                 return(FALSE);          /* didn't find that first char */
  259.                 
  260.         }
  261.  
  262.         /* else try for unanchored match of the pattern */
  263.         do {
  264.                 if (advance(p1, p2)) return(loc1 = p1, 1);
  265.         } while (*p1++);
  266.  
  267.         /* if got here, didn't match either way */
  268.         return(FALSE);
  269. }
  270.  
  271. int advance(lp, ep)
  272. /* attempt to advance match pointer by one pattern element */
  273. register unsigned char   *lp;           /* source (linebuf) ptr */
  274. register unsigned char   *ep;           /* regular expression element ptr */
  275. {
  276.         register char   *curlp;         /* save ptr for closures */ 
  277.         int             c;              /* scratch character holder */
  278.         char            *bbeg;
  279.         int             ct;             /* number of characters per match */
  280.  
  281.         for (;;)
  282.         {
  283.                 curlp = lp;             /* save old location for STAR */
  284.                 ct = 1;                 /* default to take 1 char back */
  285.                 
  286.                 switch (*ep++)
  287.                 {
  288.                 case CCHR:              /* literal character */
  289.                         c = *lp++;
  290.                         if (*ep++ == RiteCase(c)) /* if chars are equal */
  291.                                 continue;       /* matched */
  292.                         return(FALSE);          /* else return false */
  293.  
  294.                 case CDOT:              /* anything but newline */
  295.                         if (*lp++)              /* first NUL is at EOL */
  296.                                 continue;       /* keep going if didn't find */
  297.                         return(FALSE);          /* else return false */
  298.  
  299.                 case CNL:               /* start-of-line */
  300.                 case CDOL:              /* end-of-line */
  301.                         if (*lp == 0)           /* found that first NUL? */
  302.                                 continue;       /* yes, keep going */
  303.                         return(FALSE);          /* else return false */
  304.  
  305.                 case CBWD:              /* begin word */
  306.                         if (lp>linebuf && ((c = *(lp-1))=='_' || isalnum(c)))
  307.                            return(FALSE);
  308.                         continue;
  309.  
  310.                 case CEWD:              /* end word */
  311.                         if ((c = *lp)=='_' || isalnum(c))
  312.                                 return(FALSE);
  313.                         continue;
  314.  
  315.                 case CEOF:              /* end-of-address mark */
  316.                         loc2 = lp;              /* set second loc */
  317.                         return(TRUE);           /* return true */
  318.                         
  319.                 case CALF:              /* alphanumeric */
  320.                         c = *lp++;
  321.                         if (!isalnum(c))
  322.                              return(FALSE);
  323.                         if (*ep++ == 'A')
  324.                              while (isalnum(*lp)) lp++;
  325.                         continue;
  326.                         
  327.                 case CLET:              /* letter */
  328.                         c = *lp++;
  329.                         if (!isalpha(c))
  330.                                 return(FALSE);
  331.                         if (*ep++ == 'L')
  332.                            while (isalpha(*lp)) lp++;
  333.                         continue;
  334.                         
  335.                 case CDIG:              /* digit */
  336.                         c = *lp++;
  337.                         if (!isdigit(c))
  338.                                 return(FALSE);
  339.                         if (*ep++ == 'D')
  340.                            while (isdigit(*lp)) lp++;
  341.                         continue;
  342.  
  343.                 case CHEX:              /* hexdigit */
  344.                         c = *lp++;
  345.                         if (!isxdigit(c))
  346.                                 return(FALSE);
  347.                         if (*ep++ == 'H')
  348.                            while (isxdigit(*lp)) lp++;
  349.                         continue;
  350.                         
  351.                 case CSPS:              /* space */
  352.                         c = *lp++;
  353.                         if (!isspace(c))
  354.                                 return(FALSE);
  355.                         if (*ep++ == 'S')
  356.                            while (isspace(*lp)) lp++;
  357.                         continue;
  358.  
  359.                 case CCL:               /* a closure */
  360.                         c = *lp++;
  361.                         c = RiteCase(c);
  362.                         if (ep[c>>3] & bits[c & 07])    /* is char in set? */
  363.                         {
  364.                                 ep += 32;       /* then skip rest of bitmask */
  365.                                 continue;       /*   and keep going */
  366.                         }
  367.                         return(FALSE);          /* else return false */
  368.  
  369.                 case CBRA:              /* start of tagged pattern */
  370.                         brastart[*ep++] = lp;   /* mark it */
  371.                         continue;               /* and go */
  372.  
  373.                 case CKET:              /* end of tagged pattern */
  374.                         bracend[*ep++] = lp;    /* mark it */
  375.                         continue;               /* and go */
  376.  
  377.                 case CBACK: 
  378.                         bbeg = brastart[*ep];
  379.                         ct = bracend[*ep++] - bbeg;
  380.  
  381.                         if (memcmp(bbeg, lp, ct))
  382.                            return(FALSE);
  383.  
  384.                         lp += ct;
  385.                         continue;
  386.  
  387.                 case CBACK|STAR:
  388.                         bbeg = brastart[*ep];
  389.                         ct = bracend[*ep++] - bbeg;
  390.                         while(!memcmp(bbeg, lp, ct))
  391.                                 lp += ct;
  392.                         goto star;
  393.  
  394.                 case CDOT|STAR:                 /* match .* */
  395.                         while (*lp) lp++;       /* match anything */ 
  396.                         goto star;              /* now look for followers */
  397.  
  398.                 case CCHR|STAR:         /* match <literal char>* */
  399.                         while (RiteCase(*lp) == *ep) lp++;   /* match many of that char */
  400.                         ep++;                   /* to start of next element */
  401.                         goto star;              /* match it and followers */
  402.  
  403.                 case CALF|STAR:              /* alphanumeric* */
  404.                         while (isalnum(*lp)) lp++;
  405.                         if (*ep++=='a') goto star;
  406.                         goto star2;
  407.                         
  408.                 case CLET|STAR:              /* letter* */
  409.                         while (isalpha(*lp)) lp++;
  410.                         if (*ep++=='l') goto star;
  411.                         goto star2;
  412.                         
  413.                 case CDIG|STAR:              /* digit* */
  414.                         while (isdigit(*lp)) lp++;
  415.                         if (*ep++=='d') goto star;
  416.                         goto star2;
  417.                         
  418.                 case CHEX|STAR:              /* hex* */
  419.                         while (isxdigit(*lp)) lp++;
  420.                         if (*ep++=='h') goto star;
  421.                         goto star2;
  422.                         
  423.                 case CSPS|STAR:              /* space* */
  424.                         while (isspace(*lp)) lp++;
  425.                         if (*ep++=='s') goto star;
  426.                         goto star2;
  427.                         
  428.                 case CCL|STAR:               /* [...]* */
  429.                         do {
  430.                                 c = *lp++;      /* match any in set */
  431.                                 c = RiteCase(c);
  432.                         } while
  433.                                 (ep[c>>3] & bits[c & 07]);
  434.                         lp--;
  435.                         ep += 32;               /* skip past the set */
  436.                         goto star;              /* match followers */
  437.  
  438.                 star2:  ct = lp-curlp;            /* either take all or none */
  439.                 
  440.                 star:           /* the recursion part of a * or + match */
  441.                         if (lp == curlp)        /* 0 matches */
  442.                                 continue;
  443.  
  444.                         if (*ep == CCHR)
  445.                         {
  446.                                 c = ep[1];
  447.                                 do {
  448.                                         if (RiteCase(*lp) != c)
  449.                                                 continue;
  450.                                         if (advance(lp, ep))
  451.                                                 return(TRUE);
  452.                                 } while ((lp -= ct) >= curlp);
  453.                                 
  454.                                 return(FALSE);
  455.                         }
  456.  
  457.                         if (*ep == CBACK)
  458.                         {
  459.                                 c = *(brastart[ep[1]]);
  460.                                 do {
  461.                                         if (RiteCase(*lp) != c)
  462.                                                 continue;
  463.                                         if (advance(lp, ep))
  464.                                                 return(TRUE);
  465.                                 } while ((lp -= ct) >= curlp);
  466.                                 
  467.                                 return(FALSE);
  468.                         }
  469.         
  470.                         do {
  471.                                 if (lp == locs)
  472.                                         break;
  473.                                 if (advance(lp, ep))
  474.                                         return(TRUE);
  475.                         } while ((lp -= ct) >= curlp);
  476.                         
  477.                         return(FALSE);
  478.  
  479.                 default:
  480.                         fprintf(stderr, "sed: RE error, %o\n", *--ep);
  481.                 }
  482.         }  
  483. }
  484.  
  485. int substitute(ipc)
  486. /* perform s command */
  487. sedcmd  *ipc;                           /* ptr to s command struct */
  488. {
  489.         void dosub();                   /* for if we find a match */
  490.  
  491.         wordcount = -1;
  492.         
  493.         if (match(ipc->u.lhs, 0))               /* if no match */
  494.                 dosub(ipc->rhs);                /* perform it once */
  495.         else
  496.                 return(FALSE);                  /* command fails */
  497.  
  498.         if (ipc->flags.global)                  /* if global flag enabled */
  499.                 while(*loc2)                    /* cycle through possibles */
  500.                         if (match(ipc->u.lhs, 1))       /* found another */
  501.                                 dosub(ipc->rhs);        /* so substitute */
  502.                         else                            /* otherwise, */
  503.                                 break;                  /* we're done */
  504.         return(TRUE);                           /* we succeeded */
  505. }
  506.  
  507. void dosub(rhsbuf)               /* uses linebuf, genbuf, spend */
  508. /* generate substituted right-hand side (of s command) */
  509. char    *rhsbuf;        /* where to put the result */
  510. {
  511.         register char   *lp, *sp, *rp, *wp, *tp;
  512.         int             c, c1;
  513.         char            *place();
  514.  
  515.         /* copy linebuf to genbuf up to location  1 */
  516.         lp = linebuf; sp = genbuf;
  517.         while (lp < loc1) *sp++ = *lp++;
  518.  
  519.         for (rp = rhsbuf; c = *rp++; )
  520.         {
  521.                 if (c == '&')
  522.                 {
  523.                         sp = place(sp, loc1, loc2);
  524.                         continue;
  525.                 }
  526.                 else if (c == '\\')
  527.                 {
  528.                    c1 = 1;
  529.                    switch ((c=*rp++))
  530.                    {
  531.                    case 'l': cvcase = -1;
  532.                              break;
  533.                    case 'L': cvcase = -2;
  534.                              break;
  535.                    case 'u': cvcase = 1;
  536.                              break;
  537.                    case 'U': cvcase = 2;
  538.                              break;
  539.                    case 'e':
  540.                    case 'E': cvcase = 0;
  541.                              break;
  542.                    default:  if (c >= '1' && c < MAXTAGS+'1')
  543.                                 sp = place(sp, brastart[c-'1'],
  544.                                                bracend[c-'1']);
  545.                              else
  546.                                 c1 = 0;
  547.                    }
  548.                    if (c1) continue;
  549.                 }
  550.                 else if (c == '$' && isdigit(*rp))
  551.                 {
  552.                    if (wordcount<0)
  553.                    {
  554.                       wordbeg[0] = wp = wordbuf;
  555.                       wordcount = 0;
  556.                       for (tp=linebuf; wp<wordbufend && (*wp++ = *tp++); );
  557.                       *(wordbufend-1) = '\0';
  558.                       wordend[0] = wp-1;
  559.                       wp = wordbuf;
  560.                       while (*wp)
  561.                       {
  562.                          while ((c=*wp) && (c==' ' || c=='\t' || c=='\n'))
  563.                             wp++;
  564.                          if (!c) break;
  565.                          if (++wordcount < 10)
  566.                             wordbeg[wordcount] = wp;
  567.                          while ((c=*wp) && c!=' ' && c!='\t' && c!='\n')
  568.                             wp++;
  569.                          if (wordcount < 10)
  570.                             wordend[wordcount] = wp;
  571.                       }
  572.                    }
  573.                    
  574.                    c1 = *rp++ - '0';
  575.                    if (c1<=wordcount)
  576.                       sp = place(sp, wordbeg[c1], wordend[c1]);
  577.                    continue;
  578.                 }
  579.  
  580.                 *sp++ = c;
  581.                 if (sp >= genbuf + GENSIZ)
  582.                         fprintf(stderr, LTLMSG);
  583.         }
  584.         lp = loc2;
  585. /* MRY  loc2 = sp - genbuf + linebuf; */
  586.         loc2 = sp - (genbuf - linebuf);
  587.         while (*sp++ = *lp++)
  588.                 if (sp >= genbuf + GENSIZ)
  589.                         fprintf(stderr, LTLMSG);
  590.         lp = linebuf; sp = genbuf;
  591.         while (*lp++ = *sp++);
  592.         spend = lp-1;
  593. }
  594.  
  595. char *place(asp, al1, al2)               /* uses genbuf */
  596. /* place chars at *al1...*(al2 - 1) at asp... in genbuf[] */
  597. register char   *asp, *al1, *al2;
  598. {
  599.         while (al1 < al2)
  600.         {
  601.                 *asp = *al1++;
  602.                 if (cvcase<0)
  603.                    *asp = tolower(*asp);
  604.                 else if (cvcase>0)
  605.                    *asp = toupper(*asp);
  606.                 if (++asp >= genbuf + GENSIZ)
  607.                         fprintf(stderr, LTLMSG);
  608.         }
  609.         if (cvcase==1 || cvcase==-1) cvcase = 0;
  610.         return(asp);
  611. }
  612.  
  613. void listto(p1, fp)
  614. /* write a hex dump expansion of *p1... to fp */
  615. register char   *p1;            /* the source */
  616. FILE            *fp;            /* output stream to write to */
  617. {
  618.         p1--;
  619.         while(*p1++)
  620.                 if (isprint(*p1))
  621.                         putc(*p1, fp);          /* pass it through */
  622.                 else
  623.                 {
  624.                         putc('\134', fp);       /* emit a backslash */
  625.                         switch(*p1)
  626.                         {
  627.                         case '\10':     putc('b', fp); break;   /* BS */
  628.                         case '\11':     putc('t', fp); break;   /* TAB */
  629. /* \11 was \9 --MRY */
  630.                         case '\12':     putc('n', fp); break;   /* NL */
  631.                         case '\15':     putc('r', fp); break;   /* CR */
  632.                         case '\33':     putc('e', fp); break;   /* ESC */
  633.                         default:        fprintf(fp, "%02x", *p1 & 0xFF);
  634.                         }
  635.                 }
  636.         putc('\n', fp);
  637. }
  638.  
  639. void command(ipc)
  640. /* execute compiled command pointed at by ipc */
  641. sedcmd  *ipc;
  642. {
  643.         static int      didsub;                 /* true if last s succeeded */
  644.         static char     holdsp[MAXHOLD];        /* the hold space */
  645.         static char     *hspend = holdsp;       /* hold space end pointer */
  646.         register char   *p1, *p2, *p3;
  647.         unsigned char   *y1, *y2;
  648.         register int    i;
  649.         char            *execp, *getline();
  650.         void            readout();
  651.  
  652.         switch(ipc->command)
  653.         {
  654.         case ACMD:              /* append */
  655.                 *aptr++ = ipc;
  656.                 if (aptr >= appends + MAXAPPENDS)
  657.                         fprintf(stderr,
  658.                                 "sed: too many appends after line %ld\n",
  659.                                 lnum);
  660.                 *aptr = 0;
  661.                 break;
  662.  
  663.         case CCMD:              /* change pattern space */
  664.                 delete = TRUE;
  665.                 if (!ipc->flags.inrange || lastline())
  666.                         printf("%s\n", ipc->u.lhs);             
  667.                 break;
  668.  
  669.         case DCMD:              /* delete pattern space */
  670.                 delete++;
  671.                 break;
  672.  
  673.         case CDCMD:             /* delete a line in hold space */
  674.                 p1 = p2 = linebuf;
  675.                 while(*p1 != '\n')
  676.                         if (delete = (*p1++ == 0))
  677.                                 return;
  678.                 p1++;
  679.                 while(*p2++ = *p1++) continue;
  680.                 spend = p2-1;
  681.                 jump++;
  682.                 break;
  683.  
  684.         case EQCMD:             /* show current line number */
  685.                 fprintf(stdout, "%ld\n", lnum);
  686.                 break;
  687.  
  688.         case GCMD:              /* copy hold space to pattern space */
  689.                 p1 = linebuf;   p2 = holdsp;    while(*p1++ = *p2++);
  690.                 spend = p1-1;
  691.                 break;
  692.  
  693.         case CGCMD:             /* append hold space to pattern space */
  694.                 *spend++ = '\n';
  695.                 p1 = spend;     p2 = holdsp;
  696.                 while(*p1++ = *p2++)
  697.                         if (p1 >= linebuf + MAXBUF)
  698.                                 break;
  699.                 spend = p1-1;
  700.                 break;
  701.  
  702.         case HCMD:              /* copy pattern space to hold space */
  703.                 p1 = holdsp;    p2 = linebuf;   while(*p1++ = *p2++);
  704.                 hspend = p1-1;
  705.                 break;
  706.  
  707.         case CHCMD:             /* append pattern space to hold space */
  708.                 *hspend++ = '\n';
  709.                 p1 = hspend;    p2 = linebuf;
  710.                 while(*p1++ = *p2++)
  711.                         if (p1 >= holdsp + MAXBUF)
  712.                                 break;
  713.                 hspend = p1-1;
  714.                 break;
  715.  
  716.         case ICMD:              /* insert text */
  717.                 puts(ipc->u.lhs);
  718.                 break;
  719.  
  720.         case BCMD:              /* branch to label */
  721.                 jump = TRUE;
  722.                 break;
  723.  
  724.         case LCMD:              /* list text */
  725.                 listto(linebuf, (ipc->fout != NULL)?ipc->fout:stdout); break;
  726.  
  727.         case NCMD:      /* read next line into pattern space */
  728.                 if (!nflag)
  729.                         puts(linebuf);  /* flush out the current line */
  730.                 if (aptr > appends)
  731.                         readout();      /* do pending a, r commands */
  732.                 if ((execp = getline(linebuf)) == BAD)
  733.                 {
  734.                         pending = ipc;
  735.                         delete = TRUE;
  736.                         break;
  737.                 }
  738.                 spend = execp;
  739.                 break;
  740.  
  741.         case CNCMD:     /* append next line to pattern space */
  742.                 if (aptr > appends)
  743.                         readout();
  744.                 *spend++ = '\n';
  745.                 if ((execp = getline(spend)) == BAD)
  746.                 {
  747.                         pending = ipc;
  748.                         delete = TRUE;
  749.                         break;
  750.                 }
  751.                 spend = execp;
  752.                 break;
  753.  
  754.         case PCMD:              /* print pattern space */
  755.                 puts(linebuf);
  756.                 break;
  757.  
  758.         case CPCMD:             /* print one line from pattern space */
  759.                 cpcom:          /* so s command can jump here */
  760.                 for(p1 = linebuf; *p1 != '\n' && *p1 != '\0'; )
  761.                         putc(*p1++, stdout);
  762.                 putc('\n', stdout);
  763.                 break;
  764.  
  765.         case QCMD:              /* quit the stream editor */
  766.                 if (!nflag)
  767.                         puts(linebuf);  /* flush out the current line */
  768.                 if (aptr > appends)
  769.                         readout();      /* do any pending a and r commands */
  770.                 exit(0);
  771.  
  772.         case RCMD:              /* read a file into the stream */
  773.                 *aptr++ = ipc;
  774.                 if (aptr >= appends + MAXAPPENDS)
  775.                         fprintf(stderr,
  776.                                 "sed: too many reads after line %ld\n",
  777.                                 lnum);
  778.                 *aptr = 0;
  779.                 break;
  780.  
  781.         case SCMD:              /* substitute RE */
  782.                 didsub = substitute(ipc);
  783.                 if (ipc->flags.print && didsub)
  784.                         if (ipc->flags.print == TRUE)
  785.                                 puts(linebuf);
  786.                         else
  787.                                 goto cpcom;
  788.                 if (didsub && ipc->fout)
  789.                 {
  790.                         fputs(linebuf,ipc->fout);
  791.                         putc('\n',ipc->fout);
  792.                 }
  793.                 break;
  794.  
  795.         case TCMD:              /* branch on last s successful */
  796.         case CTCMD:             /* branch on last s failed */
  797.                 if (didsub == (ipc->command == CTCMD))
  798.                         break;          /* no branch if last s failed, else */
  799.                 didsub = FALSE;
  800.                 jump = TRUE;            /*  set up to jump to assoc'd label */
  801.                 break;
  802.  
  803.         case CWCMD:             /* write one line from pattern space */
  804.                 for(p1 = linebuf; *p1 != '\n' && *p1 != '\0'; )
  805.                         putc(*p1++, ipc->fout);
  806.                 putc('\n', ipc->fout);
  807.                 break;
  808.  
  809.         case WCMD:              /* write pattern space to file */
  810.                 fputs(linebuf, ipc->fout);
  811.                 putc('\n', ipc->fout);
  812.                 break;
  813.  
  814.         case XCMD:              /* exchange pattern and hold spaces */
  815.                 p1 = linebuf;   p2 = genbuf;    while(*p2++ = *p1++) continue;
  816.                 p1 = holdsp;    p2 = linebuf;   while(*p2++ = *p1++) continue;
  817.                 spend = p2 - 1;
  818.                 p1 = genbuf;    p2 = holdsp;    while(*p2++ = *p1++) continue;
  819.                 hspend = p2 - 1;
  820.                 break;
  821.  
  822.         case YCMD:
  823.                 y1 = linebuf;   y2 = ipc->u.lhs;
  824.                 while(*y1 = y2[*y1])
  825.                         y1++;
  826.                 break;
  827.         }
  828. }
  829.  
  830. char *getline(buf)
  831. /* get next line of text to be filtered */
  832. register char   *buf;           /* where to send the input */
  833. {
  834.         if (gets(buf) != NULL)
  835.         {
  836.                 lnum++;                 /* note that we got another line */
  837.                 while(*buf++);          /* find the end of the input */
  838.                 return(--buf);          /* return ptr to terminating null */ 
  839.         }
  840.         else
  841.                 return(BAD);
  842. }
  843.  
  844. int lastline()           /* decide whether this is the last line */
  845. {
  846.        register int ch;
  847.  
  848.        if (eargc)
  849.               return(FALSE);
  850.  
  851.        ch=getc(stdin);
  852.        if (ch==EOF)
  853.           return(TRUE);
  854.        ungetc(ch,stdin);
  855.        return(FALSE);
  856.  
  857. }
  858.  
  859. void readout()
  860. /* write file indicated by r command to output */
  861. {
  862.         register char   *p1;    /* character-fetching dummy */
  863.         register int    t;      /* hold input char or EOF */
  864.         FILE            *fi;    /* ptr to file to be read */
  865.  
  866.         aptr = appends - 1;     /* arrange for pre-increment to work right */
  867.         while(*++aptr)
  868.                 if ((*aptr)->command == ACMD)           /* process "a" cmd */
  869.                         puts((*aptr)->u.lhs);
  870.                 else                                    /* process "r" cmd */
  871.                 {
  872.                         if ((fi = fopen((*aptr)->u.lhs, "r")) == NULL)
  873.                                 continue;
  874.                         while((t = getc(fi)) != EOF)
  875.                                 putc((char) t, stdout);
  876.                         fclose(fi);
  877.                 }
  878.         aptr = appends;         /* reset the append ptr */
  879.         *aptr = 0;
  880. }
  881.  
  882. /* sedexec.c ends here */
  883.